home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / prospero / propsero.lha / prospero-beta.4.2e / app / ls.c < prev    next >
C/C++ Source or Header  |  1992-02-10  |  19KB  |  887 lines

  1. /*
  2.  * Derived from Berkeley source code.  Those parts are
  3.  * Copyright (c) 1989 The Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * This code is derived from software contributed to Berkeley by
  7.  * Michael Fischbein.
  8.  *
  9.  * Redistribution and use in source and binary forms are permitted
  10.  * provided that: (1) source distributions retain this entire copyright
  11.  * notice and comment, and (2) distributions including binaries display
  12.  * the following acknowledgement:  ``This product includes software
  13.  * developed by the University of California, Berkeley and its contributors''
  14.  * in the documentation or other materials provided with the distribution
  15.  * and in all advertising materials mentioning features or use of this
  16.  * software. Neither the name of the University nor the names of its
  17.  * contributors may be used to endorse or promote products derived
  18.  * from this software without specific prior written permission.
  19.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  20.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  21.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  22.  */
  23.  
  24. #ifndef lint
  25. char copyright[] =
  26. "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
  27.  All rights reserved.\n";
  28. #endif /* not lint */
  29.  
  30. #ifndef lint
  31. static char sccsid[] = "@(#)ls.c    5.42 (Berkeley) 5/17/90";
  32. #endif /* not lint */
  33.  
  34. #define  DAYSPERNYEAR (365)
  35. #define  SECSPERDAY (24*60*60)
  36. #define  UT_NAMESIZE 8
  37. #define  S_ISLNK(m)  ((S_IFLNK & m) == S_IFLNK)
  38.  
  39. #include <sys/types.h>
  40. #include <sys/stat.h>
  41. #include <stdio.h>
  42. #include <ctype.h>
  43. #include <sys/param.h>
  44. #include <sys/ioctl.h>
  45. #include <string.h>
  46. #include <errno.h>
  47. #include <grp.h>
  48. #include <pwd.h>
  49. #include <utmp.h>
  50.  
  51. #include <pcompat.h>
  52. #include <pmachine.h>
  53.  
  54. #ifdef USE_SYS_DIR_H
  55. #include <sys/dir.h>
  56. #else
  57. #include <dirent.h>
  58. #endif
  59.  
  60. extern     char        *sys_errlist[];
  61. extern  int        sys_nerr;
  62.  
  63. char            *strerror();
  64. char            *user_from_uid();
  65. char            *group_from_gid();
  66.  
  67. typedef struct _lsstruct {
  68.     char *name;            /* file name */
  69.     int len;            /* file name length */
  70.     struct stat lstat;        /* lstat(2) for file */
  71. } LS;
  72.  
  73. extern int errno;
  74.  
  75. int (*sortfcn)(), (*printfcn)();
  76. int lstat();
  77. char *emalloc();
  78.  
  79. int termwidth = 80;        /* default terminal width */
  80.  
  81. /* flags */
  82. int f_accesstime;        /* use time of last access */
  83. int f_column;            /* columnated format */
  84. int f_group;            /* show group ownership of a file */
  85. int f_ignorelink;        /* indirect through symbolic link operands */
  86. int f_inode;            /* print inode */
  87. int f_kblocks;            /* print size in kilobytes */
  88. int f_listalldot;        /* list . and .. as well */
  89. int f_listdir;            /* list actual directory, not contents */
  90. int f_listdot;            /* list files beginning with . */
  91. int f_longform;            /* long listing format */
  92. int f_needstat;            /* if need to stat files */
  93. int f_newline;            /* if precede with newline */
  94. int f_nonprint;            /* show unprintables as ? */
  95. int f_nosort;            /* don't sort output */
  96. int f_recursive;        /* ls subdirectories also */
  97. int f_reversesort;        /* reverse whatever sort is used */
  98. int f_singlecol;        /* use single column output */
  99. int f_size;            /* list size in short listing */
  100. int f_statustime;        /* use time of last mode change */
  101. int f_dirname;            /* if precede with directory name */
  102. int f_timesort;            /* sort by time vice name */
  103. int f_total;            /* if precede with "total" line */
  104. int f_type;            /* add type character for non-regular files */
  105.  
  106. char *dummyargv[2] = {"", NULL};
  107.  
  108. main(argc, argv)
  109.     int argc;
  110.     char **argv;
  111. {
  112.     extern int optind, stat();
  113.     struct winsize win;
  114.     int ch;
  115.     char *p, *getenv();
  116.     int acccmp(), modcmp(), namecmp(), prcopy(), printcol();
  117.     int printlong(), printscol(), revacccmp(), revmodcmp(), revnamecmp();
  118.     int revstatcmp(), statcmp();
  119.  
  120.     /* terminal defaults to -Cq, non-terminal defaults to -1 */
  121.     if (isatty(1)) {
  122.         f_nonprint = 1;
  123.         if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) {
  124.             if (p = getenv("COLUMNS"))
  125.                 termwidth = atoi(p);
  126.         }
  127.         else
  128.             termwidth = win.ws_col;
  129.         f_column = 1;
  130.     } else
  131.         f_singlecol = 1;
  132.  
  133.     /* root is -A automatically */
  134.     if (!getuid())
  135.         f_listdot = 1;
  136.  
  137.     /* Print sizes in kilobytes by default */
  138.     f_kblocks = 1;
  139.  
  140.     while ((ch = getopt(argc, argv, "1ACFLRacdfgiklqrstu")) != EOF) {
  141.         switch (ch) {
  142.         /*
  143.          * -1, -C and -l all override each other
  144.          * so shell aliasing works right
  145.          */
  146.         case '1':
  147.             f_singlecol = 1;
  148.             f_column = f_longform = 0;
  149.             break;
  150.         case 'C':
  151.             f_column = 1;
  152.             f_longform = f_singlecol = 0;
  153.             break;
  154.         case 'l':
  155.             f_longform = 1;
  156.             f_column = f_singlecol = 0;
  157.             break;
  158.         /* -c and -u override each other */
  159.         case 'c':
  160.             f_statustime = 1;
  161.             f_accesstime = 0;
  162.             break;
  163.         case 'u':
  164.             f_accesstime = 1;
  165.             f_statustime = 0;
  166.             break;
  167.         case 'F':
  168.             f_type = 1;
  169.             break;
  170.         case 'L':
  171.             f_ignorelink = 1;
  172.             break;
  173.         case 'R':
  174.             f_recursive = 1;
  175.             break;
  176.         case 'a':
  177.             f_listalldot = 1;
  178.             /* FALLTHROUGH */
  179.         case 'A':
  180.             f_listdot = 1;
  181.             break;
  182.         case 'd':
  183.             f_listdir = 1;
  184.             break;
  185.         case 'f':
  186.             f_nosort = 1;
  187.             break;
  188.         case 'g':
  189.             f_group = 1;
  190.             break;
  191.         case 'i':
  192.             f_inode = 1;
  193.             break;
  194.         case 'k':
  195.             f_kblocks = 1;
  196.             break;
  197.         case 'q':
  198.             f_nonprint = 1;
  199.             break;
  200.         case 'r':
  201.             f_reversesort = 1;
  202.             break;
  203.         case 's':
  204.             f_size = 1;
  205.             break;
  206.         case 't':
  207.             f_timesort = 1;
  208.             break;
  209.         default:
  210.         case '?':
  211.             usage();
  212.         }
  213.     }
  214.     argc -= optind;
  215.     argv += optind;
  216.  
  217.     /* -d turns off -R */
  218.     if (f_listdir)
  219.         f_recursive = 0;
  220.  
  221.     /* if need to stat files */
  222.     f_needstat = f_longform || f_recursive || f_timesort ||
  223.         f_size || f_type;
  224.  
  225.     /* select a sort function */
  226.     if (f_reversesort) {
  227.         if (!f_timesort)
  228.             sortfcn = revnamecmp;
  229.         else if (f_accesstime)
  230.             sortfcn = revacccmp;
  231.         else if (f_statustime)
  232.             sortfcn = revstatcmp;
  233.         else /* use modification time */
  234.             sortfcn = revmodcmp;
  235.     } else {
  236.         if (!f_timesort)
  237.             sortfcn = namecmp;
  238.         else if (f_accesstime)
  239.             sortfcn = acccmp;
  240.         else if (f_statustime)
  241.             sortfcn = statcmp;
  242.         else /* use modification time */
  243.             sortfcn = modcmp;
  244.     }
  245.  
  246.     /* select a print function */
  247.     if (f_singlecol)
  248.         printfcn = printscol;
  249.     else if (f_longform)
  250.         printfcn = printlong;
  251.     else
  252.         printfcn = printcol;
  253.  
  254.     if (argc) doargs(argc, argv);
  255.     else doargs(1,dummyargv);
  256.     exit(0);
  257. }
  258.  
  259. static char path[MAXPATHLEN + 1];
  260. static char *endofpath = path;
  261.  
  262. doargs(argc, argv)
  263.     int argc;
  264.     char **argv;
  265. {
  266.     register LS *dstatp, *rstatp;
  267.     register int cnt, dircnt, maxlen, regcnt;
  268.     LS *dstats, *rstats;
  269.     struct stat sb;
  270.     int (*statfcn)(), stat(), lstat();
  271.     char top[MAXPATHLEN + 1];
  272.     u_long blocks;
  273.     long    r_st_btotal;
  274.     long    r_st_maxlen;
  275.  
  276.     /*
  277.      * walk through the operands, building separate arrays of LS
  278.      * structures for directory and non-directory files.
  279.      */
  280.     dstats = rstats = NULL;
  281.     statfcn = (f_longform || f_listdir) && !f_ignorelink ? lstat : stat;
  282.     for (dircnt = regcnt = 0; *argv; ++argv) {
  283.         if (statfcn(*argv, &sb)) {
  284.             if (statfcn != stat || lstat(*argv, &sb)) {
  285.                 (void)fflush(stdout);
  286.                 (void)fprintf(stderr, "ls: %s: %s\n", *argv,
  287.                       strerror(errno));
  288.                 if (errno == ENOENT)
  289.                 continue;
  290.                 exit(1);
  291.             }
  292.         }
  293.         if (S_ISDIR(sb.st_mode) && !f_listdir) {
  294.             if (!dstats)
  295.                 dstatp = dstats = (LS *)emalloc((u_int)argc *
  296.                     (sizeof(LS)));
  297.             dstatp->name = *argv;
  298.             dstatp->lstat = sb;
  299.             ++dstatp;
  300.             ++dircnt;
  301.         }
  302.         else {
  303.             if (!rstats) {
  304.                 rstatp = rstats = (LS *)emalloc((u_int)argc *
  305.                     (sizeof(LS)));
  306.                 blocks = 0;
  307.                 maxlen = -1;
  308.             }
  309.             rstatp->name = *argv;
  310.             rstatp->lstat = sb;
  311.  
  312.             /* save name length for -C format */
  313.             rstatp->len = strlen(*argv);
  314.  
  315.             if (f_nonprint)
  316.                 prcopy(*argv, *argv, rstatp->len);
  317.  
  318.             /* calculate number of blocks if -l/-s formats */
  319.             if (f_longform || f_size)
  320.                 blocks += sb.st_blocks;
  321.  
  322.             /* save max length if -C format */
  323.             if (f_column && maxlen < rstatp->len)
  324.                 maxlen = rstatp->len;
  325.  
  326.             ++rstatp;
  327.             ++regcnt;
  328.         }
  329.     }
  330.     /* display regular files */
  331.     if (regcnt) {
  332.         displaydir("", rstats, regcnt, blocks, maxlen);
  333.         f_newline = f_dirname = 1;
  334.     }
  335.     /* display directories */
  336.     if (dircnt) {
  337.         register char *p;
  338.  
  339.         f_total = 1;
  340.         if (dircnt > 1) {
  341.             (void)getwd(top);
  342.             qsort((char *)dstats, dircnt, sizeof(LS), sortfcn);
  343.             f_dirname = 1;
  344.         }
  345.         for (cnt = 0; cnt < dircnt; ++dstats) {
  346.             for (endofpath = path, p = dstats->name;
  347.                 *endofpath = *p++; ++endofpath);
  348.             subdir("",dstats);
  349.             f_newline = 1;
  350.             if (++cnt < dircnt && chdir(top)) {
  351.                 (void)fprintf(stderr, "ls: %s: %s\n",
  352.                     top, strerror(errno));
  353.                 exit(1);
  354.             }
  355.         }
  356.     }
  357. }
  358.  
  359. displaydir(subdirname, stats, num, blocks, maxlen)
  360.         char *subdirname;
  361.     LS *stats;
  362.     register int num;
  363.         long blocks;
  364.         long maxlen;
  365. {
  366.     register char *p, *savedpath;
  367.     LS *lp;
  368.  
  369.     if (num > 1 && !f_nosort) {
  370.         u_long save1, save2;
  371.         qsort((char *)stats, num, sizeof(LS), sortfcn);
  372.     }
  373.  
  374.     printfcn(subdirname, stats, num, blocks, maxlen);
  375.  
  376.     if (f_recursive) {
  377.         savedpath = endofpath;
  378.         for (lp = stats; num--; ++lp) {
  379.             if (!S_ISDIR(lp->lstat.st_mode))
  380.                 continue;
  381.             p = lp->name;
  382.             if (p[0] == '.' && (!p[1] || p[1] == '.' && !p[2]))
  383.                 continue;
  384.             if (endofpath != path && endofpath[-1] != '/')
  385.                 *endofpath++ = '/';
  386.             for (; *endofpath = *p++; ++endofpath);
  387.             f_newline = f_dirname = f_total = 1;
  388.             subdir(subdirname,lp);
  389.             *(endofpath = savedpath) = '\0';
  390.         }
  391.     }
  392. }
  393.  
  394. subdir(wdir,lp)
  395.         char    *wdir;
  396.     LS *lp;
  397. {
  398.         char    sbdirname[MAXPATHLEN];
  399.     LS *stats;
  400.     int num;
  401.     char *names;
  402.     long    blocks;
  403.     int    maxlen;
  404.  
  405.     if(*wdir) sprintf(sbdirname,"%s/%s",wdir,lp->name);
  406.     else strcpy(sbdirname,lp->name);
  407.  
  408.     if (f_newline)
  409.         (void)putchar('\n');
  410.     if (f_dirname)
  411.         (void)printf("%s:\n", path);
  412.  
  413.     if (num = tabdir(sbdirname, lp, &stats, &names, &blocks, &maxlen)) {
  414.         displaydir(sbdirname, stats, num, blocks, maxlen);
  415.         (void)free((char *)stats);
  416.         (void)free((char *)names);
  417.     }
  418. }
  419.  
  420. tabdir(dirname, lp, s_stats, s_names, blocksp, maxlenp)
  421.         char    *dirname;
  422.     LS *lp, **s_stats;
  423.     char **s_names;
  424.         u_long    *blocksp;
  425.         int    *maxlenp;
  426. {
  427.     register DIR     *dirp;
  428.     register int     cnt, maxentry, maxlen;
  429.     register char     *p, *names;
  430. #define NAMES_BLSIZ 2048
  431.     int              names_len = 4*NAMES_BLSIZ;
  432.     int        names_off;
  433.     struct dirent     *dp;
  434.     u_long         blocks;
  435.     LS         *stats;
  436.     char        newfname[MAXPATHLEN];
  437.  
  438.  
  439.     if (!(dirp = opendir(dirname))) {
  440.         (void)fprintf(stderr, "ls: %s: %s\n", lp->name,
  441.             strerror(errno));
  442.         return(0);
  443.     }
  444.     blocks = maxentry = maxlen = 0;
  445.     stats = NULL;
  446.     for (cnt = 0; dp = readdir(dirp);) {
  447.         /* this does -A and -a */
  448.         p = dp->d_name;
  449.         if (p[0] == '.') {
  450.             if (!f_listdot)
  451.                 continue;
  452.             if (!f_listalldot && (!p[1] || p[1] == '.' && !p[2]))
  453.                 continue;
  454.         }
  455.         if (cnt == maxentry) {
  456.             if (!maxentry)
  457.                 *s_names = names =     emalloc(names_len);
  458.  
  459.             if((names_len - (names_off = names - *s_names))
  460.                < (2*NAMES_BLSIZ)) {
  461.                 names_len += 2*NAMES_BLSIZ;
  462.                 *s_names = (char *) realloc(*s_names,names_len);
  463.                 names = *s_names + names_off;
  464.             }
  465. #define    DEFNUM    256
  466.             maxentry += DEFNUM;
  467.  
  468.              if (stats==NULL) 
  469.                  *s_stats = stats = 
  470.                 (LS *) emalloc((u_int)maxentry * sizeof (LS));
  471.                  else if (!(*s_stats = stats = 
  472.                    (LS *) realloc((char *)stats,
  473.                       (u_int)maxentry * sizeof(LS))))
  474.                 nomem();
  475.         }
  476.  
  477.         if(*dirname) sprintf(newfname,"%s/%s",dirname,dp->d_name);
  478.         else strcpy(newfname,dp->d_name);
  479.  
  480.         if (f_needstat && lstat(newfname, &stats[cnt].lstat)) {
  481.             /*
  482.              * don't exit -- this could be an NFS mount that has
  483.              * gone away.  Flush stdout so the messages line up.
  484.              */
  485.             (void)fflush(stdout);
  486.             (void)fprintf(stderr, "ls: %s: %s\n",
  487.                   dp->d_name, strerror(errno));
  488.             continue;
  489.         }
  490.         stats[cnt].name = names;
  491.  
  492.         if (f_nonprint)
  493.             prcopy(dp->d_name, names, (int)dp->d_namlen);
  494.         else
  495.             bcopy(dp->d_name, names, (int)dp->d_namlen);
  496.         names += dp->d_namlen;
  497.         *names++ = '\0';
  498.  
  499.         /*
  500.          * get the inode from the directory, so the -f flag
  501.          * works right.
  502.          */
  503.         stats[cnt].lstat.st_ino = dp->d_ino;
  504.  
  505.         /* save name length for -C format */
  506.         stats[cnt].len = dp->d_namlen;
  507.  
  508.         /* calculate number of blocks if -l/-s formats */
  509.         if (f_longform || f_size)
  510.             blocks += stats[cnt].lstat.st_blocks;
  511.  
  512.         /* save max length if -C format */
  513.         if (f_column && maxlen < (int)dp->d_namlen)
  514.             maxlen = dp->d_namlen;
  515.         ++cnt;
  516.     }
  517.     (void)closedir(dirp);
  518.  
  519.     if (cnt) {
  520.         *blocksp = blocks;
  521.         *maxlenp = maxlen;
  522.     } else if (stats) {
  523.         (void)free((char *)stats);
  524.         (void)free((char *)names);
  525.     }
  526.     return(cnt);
  527. }
  528.  
  529. printscol(dirname, stats, num, blocks, maxlen)
  530.         char  *dirname;
  531.     register LS *stats;
  532.     register int num;
  533.     long blocks;
  534.     long maxlen;
  535. {
  536.     for (; num--; ++stats) {
  537.         (void)printaname(stats);
  538.         (void)putchar('\n');
  539.     }
  540. }
  541.  
  542. printlong(dirname, stats, num , blocks, maxlen)
  543.         char *dirname;
  544.     LS *stats;
  545.     register int num;
  546.     u_long blocks;
  547.     int    maxlen ;
  548. {
  549.     extern int errno;
  550.     char modep[15];
  551.  
  552.     if (f_total)
  553.         (void)printf("total %lu\n", f_kblocks ?
  554.             howmany(blocks, 2) :
  555.             blocks);
  556.     for (; num--; ++stats) {
  557.         if (f_inode)
  558.             (void)printf("%6lu ", stats->lstat.st_ino);
  559.         if (f_size)
  560.             (void)printf("%4ld ", f_kblocks ?
  561.                 howmany(stats->lstat.st_blocks, 2) :
  562.                 stats->lstat.st_blocks);
  563.         (void)strmode(stats->lstat.st_mode, modep);
  564.         (void)printf("%s %3u %-*s ", modep, stats->lstat.st_nlink,
  565.             UT_NAMESIZE, user_from_uid((uid_t) stats->lstat.st_uid));
  566.         if (f_group)
  567.             (void)printf("%-*s ", UT_NAMESIZE,
  568.                 group_from_gid((gid_t) stats->lstat.st_gid));
  569.         if (S_ISCHR(stats->lstat.st_mode) ||
  570.             S_ISBLK(stats->lstat.st_mode))
  571.             (void)printf("%3d, %3d ", major(stats->lstat.st_rdev),
  572.                 minor(stats->lstat.st_rdev));
  573.         else
  574.             (void)printf("%8ld ", stats->lstat.st_size);
  575.         if (f_accesstime)
  576.             printtime(stats->lstat.st_atime);
  577.         else if (f_statustime)
  578.             printtime(stats->lstat.st_ctime);
  579.         else
  580.             printtime(stats->lstat.st_mtime);
  581.         (void)printf("%s", stats->name);
  582.         if (f_type)
  583.             (void)printtype(stats->lstat.st_mode);
  584.         if (S_ISLNK(stats->lstat.st_mode))
  585.             printlink(dirname,stats->name);
  586.         (void)putchar('\n');
  587.     }
  588. }
  589.  
  590. printcol(dirname, stats, num, blocks, maxlen)
  591.         char    *dirname;
  592.     LS *stats;
  593.     int num;
  594.     u_long blocks;
  595.     int maxlen;
  596. {
  597.     extern int termwidth;
  598.     register int base, chcnt, cnt, col, colwidth;
  599.     int endcol, numcols, numrows, row;
  600.  
  601.     colwidth = maxlen + 2;
  602.     if (f_inode)
  603.         colwidth += 6;
  604.     if (f_size)
  605.         colwidth += 5;
  606.     if (f_type)
  607.         colwidth += 1;
  608.  
  609.     if (termwidth < 2 * colwidth) {
  610.         printscol(dirname, stats, num, blocks, maxlen);
  611.         return;
  612.     }
  613.  
  614.     numcols = termwidth / colwidth;
  615.     numrows = num / numcols;
  616.     if (num % numcols)
  617.         ++numrows;
  618.  
  619.     if (f_size && f_total)
  620.         (void)printf("total %lu\n", f_kblocks ?
  621.             howmany(blocks, 2) : blocks);
  622.     for (row = 0; row < numrows; ++row) {
  623.         endcol = colwidth;
  624.         for (base = row, chcnt = col = 0; col < numcols; ++col) {
  625.             chcnt += printaname(stats + base);
  626.             if ((base += numrows) >= num)
  627.                 break;
  628.             while ((cnt = chcnt + 1) <= endcol) {
  629.                 (void)putchar(' ');
  630.                 chcnt = cnt;
  631.             }
  632.             endcol += colwidth;
  633.         }
  634.         putchar('\n');
  635.     }
  636. }
  637.  
  638. /*
  639.  * print [inode] [size] name
  640.  * return # of characters printed, no trailing characters
  641.  */
  642. printaname(lp)
  643.     LS *lp;
  644. {
  645.     int chcnt;
  646.  
  647.     chcnt = 0;
  648.     if (f_inode) {
  649.         printf("%5lu ", lp->lstat.st_ino);
  650.         chcnt += 6;
  651.     }
  652.     if (f_size) {
  653.         printf("%4ld ", f_kblocks ?
  654.            howmany(lp->lstat.st_blocks, 2) : lp->lstat.st_blocks);
  655.         chcnt += 5;
  656.     }
  657.     printf("%s", lp->name);
  658.     chcnt += strlen(lp->name);
  659.  
  660.     if (f_type) chcnt += printtype(lp->lstat.st_mode);
  661.  
  662.     return(chcnt);
  663. }
  664.  
  665. printtime(ftime)
  666.     time_t ftime;
  667. {
  668.     int i;
  669.     char *longstring, *ctime();
  670.     time_t time();
  671.  
  672.     if(ftime == 0) fputs("-            ",stdout);
  673.     else {
  674.  
  675.         DISABLE_PFS(longstring = ctime((long *)&ftime));
  676.         for (i = 4; i < 11; ++i)
  677.         (void)putchar(longstring[i]);
  678.  
  679. #define    SIXMONTHS    ((DAYSPERNYEAR / 2) * SECSPERDAY)
  680.         if (ftime + SIXMONTHS > time((time_t *)NULL))
  681.         for (i = 11; i < 16; ++i)
  682.             (void)putchar(longstring[i]);
  683.         else {
  684.         (void)putchar(' ');
  685.         for (i = 20; i < 24; ++i)
  686.             (void)putchar(longstring[i]);
  687.         }
  688.         (void)putchar(' ');
  689.     }
  690. }
  691.  
  692. printtype(mode)
  693.     mode_t mode;
  694. {
  695.     switch(mode & S_IFMT) {
  696.     case S_IFDIR:
  697.         (void)putchar('/');
  698.         return(1);
  699.     case S_IFLNK:
  700.         (void)putchar('@');
  701.         return(1);
  702.     case S_IFSOCK:
  703.         (void)putchar('=');
  704.         return(1);
  705.     }
  706.     if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
  707.         (void)putchar('*');
  708.         return(1);
  709.     }
  710.     return(0);
  711. }
  712.  
  713. printlink(dirname, name)
  714.     char *dirname;
  715.     char *name;
  716. {
  717.         char    linkname[MAXPATHLEN];
  718.     int lnklen;
  719.     char path[MAXPATHLEN + 1];
  720.  
  721.     if(*dirname) sprintf(linkname,"%s/%s",dirname, name);
  722.     else strcpy(linkname,name);
  723.  
  724.     if ((lnklen = readlink(linkname, path, MAXPATHLEN)) == -1) {
  725.         fflush(stdout);
  726.         (void)fprintf(stderr, "\nls: %s: %s", name, strerror(errno));
  727.         fflush(stderr);
  728.         return;
  729.     }
  730.     path[lnklen] = '\0';
  731.     (void)printf(" -> %s", path);
  732. }
  733.  
  734.  
  735. prcopy(src, dest, len)
  736.     register char *src, *dest;
  737.     register int len;
  738. {
  739.     register int ch;
  740.  
  741.     while(len--) {
  742.         ch = *src++;
  743.         *dest++ = isprint(ch) ? ch : '?';
  744.     }
  745. }
  746.  
  747. char
  748. *emalloc(size)
  749.     u_int size;
  750. {
  751.     char *retval, *malloc();
  752.  
  753.     if (!(retval = malloc(size)))
  754.         nomem();
  755.     return(retval);
  756. }
  757.  
  758. nomem()
  759. {
  760.     (void)fprintf(stderr, "ls: out of memory.\n");
  761.     exit(1);
  762. }
  763.  
  764. usage()
  765. {
  766.     (void)fprintf(stderr, "usage: ls [-1ACFLRacdfgiklqrstu] [file ...]\n");
  767.     exit(1);
  768. }
  769.  
  770.  
  771.  
  772. namecmp(a, b)
  773.     LS *a, *b;
  774. {
  775.     return(strcmp(a->name, b->name));
  776. }
  777.  
  778. revnamecmp(a, b)
  779.     LS *a, *b;
  780. {
  781.     return(strcmp(b->name, a->name));
  782. }
  783.  
  784. modcmp(a, b)
  785.     LS *a, *b;
  786. {
  787.     return(a->lstat.st_mtime < b->lstat.st_mtime);
  788. }
  789.  
  790. revmodcmp(a, b)
  791.     LS *a, *b;
  792. {
  793.     return(b->lstat.st_mtime < a->lstat.st_mtime);
  794. }
  795.  
  796. acccmp(a, b)
  797.     LS *a, *b;
  798. {
  799.     return(a->lstat.st_atime < b->lstat.st_atime);
  800. }
  801.  
  802. revacccmp(a, b)
  803.     LS *a, *b;
  804. {
  805.     return(b->lstat.st_atime < a->lstat.st_atime);
  806. }
  807.  
  808. statcmp(a, b)
  809.     LS *a, *b;
  810. {
  811.     return(a->lstat.st_ctime < b->lstat.st_ctime);
  812. }
  813.  
  814. revstatcmp(a, b)
  815.     LS *a, *b;
  816. {
  817.     return(b->lstat.st_ctime < a->lstat.st_ctime);
  818. }
  819.  
  820. char *strerror(number)
  821.     int        number;
  822.     {
  823.     if((number > 0) && (number < sys_nerr))
  824.         return(sys_errlist[number]); 
  825.     else return("Unknown Error");
  826.     }
  827.  
  828. strmode(mode,modestr)
  829.     short    mode;
  830.     char    *modestr;
  831.     {
  832.     strcpy(modestr,"----------");
  833.  
  834.     if(mode & S_IFDIR) modestr[0] = 'd';
  835.     if((mode & S_IFLNK) == S_IFLNK) modestr[0] = 'l';
  836.     if(mode & S_IREAD) modestr[1] = 'r';
  837.     if(mode & S_IWRITE) modestr[2] = 'w';
  838.     if(mode & S_IEXEC) modestr[3] = 'x';
  839.     if(mode & S_ISUID) modestr[3] = 's';
  840.     if(mode & (S_IREAD>>3)) modestr[4] = 'r';
  841.     if(mode & (S_IWRITE>>3)) modestr[5] = 'w';
  842.     if(mode & (S_IEXEC>>3)) modestr[6] = 'x';
  843.     if(mode & S_ISGID) modestr[6] = 's';
  844.     if(mode & (S_IREAD>>6)) modestr[7] = 'r';
  845.     if(mode & (S_IWRITE>>6)) modestr[8] = 'w';
  846.     if(mode & (S_IEXEC>>6)) modestr[9] = 'x';
  847.     }
  848.  
  849.  
  850. char *
  851. user_from_uid(uid)
  852.     uid_t        uid;
  853.     {
  854.     static char    uidstring[10];
  855.     struct passwd *pwent;
  856.  
  857.     if(uid == (uid_t) -1) return("-");
  858.  
  859.     DISABLE_PFS(pwent =  getpwuid(uid));
  860.  
  861.     if (pwent == NULL) {
  862.         sprintf(uidstring,"%d",uid);
  863.         return(uidstring);
  864.     }
  865.     else return(pwent->pw_name);
  866.     }
  867.  
  868.  
  869. char *
  870. group_from_gid(gid)
  871.     gid_t        gid;
  872.     {
  873.     static char    gidstring[10];
  874.     struct group     *grent;
  875.  
  876.     if(gid == (gid_t) -1) return("-");
  877.  
  878.     DISABLE_PFS(grent =  getgrgid(gid));
  879.  
  880.     if (grent == NULL) {
  881.         sprintf(gidstring,"%d",gid);
  882.         return(gidstring);
  883.     }
  884.     else return(grent->gr_name);
  885.     }
  886.  
  887.